//Copyright 2008 Kristian Gundry And Rune Juhl-Petersen
//This file is part of Plain.

//Plain is free software: you can redistribute it and/or modify
//it under the terms of the GNU Lesser General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//any later version.

//Plain is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU Lesser General Public License for more details.

//You should have received a copy of the GNU Lesser General Public License
//along with Plain.  If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Reflection;
using System.Web.UI.WebControls;
using Plain;
using Plain.Data;
using System.Runtime.Remoting;
using Plain.Web.Configuration;
using Plain.Mapping;
using System.Collections;

namespace Plain.Web.Utilities.FormBinders
{
    /// <summary>
    /// A class with four methods <see cref="BindObjectToControls"/>, <see cref="BindControlsToObject"/>, 
    /// <see cref="BindObjectToPage"/> and <see cref="BindPageToObject"/>
    /// used to bind the values of and object's properties with web <see cref="Control"/>s or web <see cref="Page"/>s that have their
    /// ID property set to the name of the object property.
    /// </summary>
	public class PlainBinding : FormBinding
    {
        #region Overrides

        /// <summary>
        /// Handle complex properties when binding a control to an object
        /// </summary>        
        /// <param name="list">The list control</param>
        /// <param name="objProperty">Object Property matching the lists id</param>
        /// <returns>Returns true if property handled by HandleComplexPropertiesObjectToControl</returns>
        protected override bool HandleComplexPropertiesControlToObject(Object obj, ListControl list, PropertyInfo objProperty)
        {
            IDaoFactory daoFactory = PlainWebApplication.Config.DaoFactory;
            Type[] interfaces = objProperty.PropertyType.GetInterfaces();
            bool found = false;
            foreach (Type type in interfaces)
            {
                if (type == typeof(IBusinessEntity<>))
                {
                    found = true;
                }
            }

            if (found)
            {
                if (list.SelectedItem != null)
                {
                    if (!string.IsNullOrEmpty(list.SelectedValue))
                    {                        
                        object id = Convert.ChangeType(list.SelectedValue, objProperty.PropertyType.GetProperty("Id").PropertyType);

                        object Dao = null;

                        Type dft = daoFactory.GetType();
                        MethodInfo[] methods = dft.GetMethods();
                        MethodInfo g = null;
                        object value = null;

                        foreach (MethodInfo m in methods)
                        {
                            if (m.Name == "GetDao" && m.IsGenericMethod)
                            {
                                g = m.MakeGenericMethod(objProperty.PropertyType, objProperty.PropertyType.GetProperty("Id").PropertyType);
                                break;
                            }
                        }

                        if (g != null)
                            Dao = g.Invoke(daoFactory, null);

                        Type dt = Dao.GetType();
                        MethodInfo dm = dt.GetMethod("Get");

                        value = dm.Invoke(Dao, new object[] { id });
                        
                        if (value != null)
                        {
                            objProperty.SetValue(obj, value, null);
                        }
                    }
                    else
                    {
                        objProperty.SetValue(obj, null, null);
                    }
                }
            } 
            return found;
        }
        
        /// <summary>
        /// Handle complex properties when binding an object to control
        /// </summary>        
        /// <param name="list">The list control</param>
        /// <param name="objProperty">Object Property matching the lists id</param>
        /// <returns>Returns true if property handled by HandleComplexPropertiesObjectToControl</returns>
        protected override bool HandleComplexPropertiesObjectToControl(Object obj, ListControl list, PropertyInfo objProperty)
        {
            Type[] interfaces = objProperty.PropertyType.GetInterfaces();
            bool found = false;

            //have to look all interfaces because of error in .net framework
            foreach (Type type in interfaces)
            {
                if (type == typeof(IBusinessEntity<>))
                {
                    found = true;
                }
            }

            if (found)
            {   //implements IBusinessEntity
                object member = objProperty.GetValue(obj, null);
                if (member != null)
                {
                    //set listvalue
                    list.SelectedValue = (Convert.ChangeType(member.GetType().GetProperty("Id").GetValue(member, null), objProperty.PropertyType.GetProperty("Id").PropertyType)).ToString();
                }
            }
            return found;
        }

        /// <summary>
        /// Handles Associated labels text value. 
        /// If a label exits with a AssociatedControlId matching the parameter name.
        /// This metode is used to set the text of the label accordingly.
        /// </summary>
        /// <param name="objectType">The type of the object property</param>
        /// <param name="propertyName">The name of the property</param>
        /// <param name="name"></param>
        protected override void BindObjectNameToAssociatedControl(Type objectType, string propertyName, Control container)
        {
            foreach (Control con in container.Controls)
            {
                Label label = con as Label;
                if (label != null)
                {
                    if (label.AssociatedControlID == propertyName)
                    {
                        IMapper mapper = PlainWebApplication.Config.DomainMapper;
                        IDictionary<string, string> mappings = mapper.GetMapping(objectType);
                        if (label != null)
                        {
                            label.Text = mappings[propertyName];
                        }
                        break;
                    }
                }
            }
        }
        
        #endregion
    }
}